open Ast

let string_of_arith_operator = function
    Add -> "+"
  | Sub -> "-"
  | Mul -> "*"
  | Div -> "/"

let string_of_cond_operator = function
    Lt  -> "<"
  | Leq -> "<="
  | Gt  -> ">" 
  | Geq -> ">="
  | Eq  -> "="
  | Neq -> "!="
  | And -> "&&"
  | Or  -> "||"

let string_of_set_operator = function
    Union  -> "%+"
  | Intersect  -> "%="
  | Difference -> "%-"

let string_of_signop = function
    SAdd -> "+"
  | SSub -> "-"


let rec string_of_expression = function
    ArithmeticExpression(e1,a_op,e2) ->
          string_of_expression e1 ^ " " ^ string_of_arith_operator a_op ^ " " ^ string_of_expression e2
  | ConditionalExpression(e1,c_op,e2) ->
          string_of_expression e1 ^ " " ^ string_of_cond_operator c_op ^ " " ^ string_of_expression e2
  | ArrayExpression (el1,el2,s) -> 
		"[" ^ String.concat ", " (List.map string_of_expression el1) ^ "][" 
		  ^  String.concat ", " (List.map string_of_expression el2) ^ "]" ^ s
  | ArrayNumber (e1,e2,s) -> "[" ^ string_of_expression e1 ^ "][" ^ string_of_expression e2 ^ "]" ^ s
  | Literal(sign_op, lit) -> string_of_signop sign_op ^ string_of_int lit
  | Id(sign_op, str) -> string_of_signop sign_op ^ str
  | Increment(s) -> s ^ " ++"
  | Decrement(s) -> s ^ " --"
  | Minus(e) -> "- " ^ string_of_expression e
  | Range(e1,e2) -> string_of_expression e1 ^ " .. " ^ string_of_expression e2
  | SimpleAssignmentExpression(str,e) -> str ^ " = " ^ string_of_expression e
  | ArrayAssignmentExpression(e1,e2) -> string_of_expression e1 ^ " = " ^ string_of_expression e2
  | HashExpression(e) -> "# " ^ string_of_expression e
  | PlusExpression(e) -> "+ " ^ string_of_expression e
  | SetExpression(s_op,e1,e2) -> string_of_set_operator s_op ^ "( " ^ string_of_expression e1 ^ " , " ^ string_of_expression e2 ^ " )\n"
  | Concatenate(e1,e2) -> string_of_expression e1 ^ "++" ^ string_of_expression e2
  | Insert(e1,e2) -> string_of_expression e1 ^ " <- " ^ "(InitializeList)\n"
  | Delete(e1,e2) -> string_of_expression e1 ^ " -> " ^ string_of_expression e2
  | ArraySingleInitialiseExpression(e,el) -> string_of_expression e ^ " = " ^  "ArraySingleInitialiseExpression."
  | ArrayMultiInitialiseExpression(e,ell) -> string_of_expression e ^ " = " ^  "ArrayMultiInitialiseExpression."
  | Noexpr -> ""
  

let rec string_of_statement = function
    Expression(e) -> string_of_expression e
  | If(e,sl1,sl2) -> "if(" ^ string_of_expression e ^ ")\n{\n" ^ String.concat "\n" (List.map string_of_statement sl1) ^ 
                      "\n}\nelse\n{\n" ^ String.concat "\n" (List.map string_of_statement sl2) ^ "\n}\n"
  | For(e1,e2,e3,s) -> "for(" ^ string_of_expression e1 ^ " ; " ^ string_of_expression e2 ^ " ; " ^
                                   string_of_expression e3 ^ ")\n{\n" ^ String.concat "\n" (List.map string_of_statement s) ^ "\n}\n"
  | Show(e) -> string_of_expression e
  | FunctionDeclaration (s, el,sl,e) -> 
		"function " ^ s ^ "(" ^  String.concat "," (List.map string_of_expression el) ^ ")" ^ "{\n" ^
		String.concat "\n" (List.map string_of_statement sl) ^ string_of_expression e ^ "\n}\n" 
  | FunctionCall (s, el) -> s ^ "(" ^  String.concat "," (List.map string_of_expression el) ^ ");" 
  | FunctionSimpleAssignment(s,stmt) -> s ^ " = " ^ "function call"
  | FunctionArrayAssignment(expr,stmt) -> "[] = function call" 
  | ShowStr(s) -> s
  | ShowList(stmt_l) -> "show(" ^ String.concat "," (List.map string_of_statement stmt_l) ^  ");"


let string_of_compilationUnit (statements)  = 
    String.concat "\n" (List.map string_of_statement statements)
